package com.xiaoshuidi.cloud.module.iot.service.impl.thirdPartImpl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xiaoshuidi.cloud.module.iot.api.device.vo.AmmeterInfoResModel;
import com.xiaoshuidi.cloud.module.iot.controller.admin.doorlock.vo.OperateThirdDeviceRequestModel;
import com.xiaoshuidi.cloud.module.iot.controller.admin.doorlock.vo.OperateThirdDeviceResponseModel;
import com.xiaoshuidi.cloud.module.iot.controller.admin.doorlock.vo.PullThirdDeviceRequestModel;
import com.xiaoshuidi.cloud.module.iot.dal.model.AccessTokenRequestModel;
import com.xiaoshuidi.cloud.module.iot.dal.model.AccessTokenResponseModel;
import com.xiaoshuidi.cloud.module.iot.dal.pojo.TbDeviceDo;
import com.xiaoshuidi.cloud.module.iot.dal.repository.DeviceRepository;
import com.xiaoshuidi.cloud.module.iot.enums.BrandEnum;
import com.xiaoshuidi.cloud.module.iot.enums.DeviceTypeEnum;
import com.xiaoshuidi.cloud.module.iot.service.AllAbstractThirdInstanceService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 杭州西子电表对接
 */
@Service("hangZhouXiZiInstanceServiceImpl")
public class HangZhouXiZiInstanceServiceImpl extends AllAbstractThirdInstanceService {

    private final static Logger LOGGER = LoggerFactory.getLogger(HangZhouXiZiInstanceServiceImpl.class);

    @Value("${hangzhouxizi.queryPowerInfoList.url:http://8.136.147.44:8099/svrBankAbutment.asmx/QueryPowerInfoList}")
    private String queryPowerInfoListUrl;

    @Value("${hangzhouxizi.changePowerState.url:http://8.136.147.44:8099/svrBankAbutment.asmx/ChangePowerState}")
    private String changePowerStateUrl;

    @Value("${hangzhouxizi.QueryPowerInfo.url:http://8.136.147.44:8099/svrBankAbutment.asmx/QueryPowerInfo}")
    private String QueryPowerInfoUrl;

    @Autowired
    private DeviceRepository deviceDataAccess;


    @Override
    public String getBrand() {
        return BrandEnum.HANGZHOUXIZI.getBrand();
    }

    @Override
    public AccessTokenResponseModel getAccessToken(AccessTokenRequestModel accessTokenRequestModel) throws Exception {
        String appId = accessTokenRequestModel.getAppId();
        String appKey = accessTokenRequestModel.getAppKey();
        //由于之前的老逻辑全部走这个获取token,不能为空，所以该厂商没有token也需要伪造，后续全部通过这个token获取appid和秘钥
        AccessTokenResponseModel accessTokenResponseModel = new AccessTokenResponseModel();
        accessTokenResponseModel.setAccessToken(appId+"|"+appKey);
        accessTokenResponseModel.setExpireTime(90L);
        return accessTokenResponseModel;
    }

    /**
     * 拉取设备
     * @param pullThirdDeviceRequestModel
     * @return
     * @throws Exception
     */
    @Override
    public List<TbDeviceDo> getDevice(PullThirdDeviceRequestModel pullThirdDeviceRequestModel) throws Exception {
        List<TbDeviceDo> tbDeviceDos = new ArrayList<>();
        String[] accessToken = pullThirdDeviceRequestModel.getAccessToken().split("\\|");
        String loginName = "";
        String loginKey = "";
        if(accessToken.length==2){
            loginName=accessToken[0];
            loginKey=accessToken[1];
        }
        if(StrUtil.isBlank(loginName)||StrUtil.isBlank(loginKey)){
            return tbDeviceDos;
        }
        long time = System.currentTimeMillis()/1000;
        String text = loginName + "QueryPowerInfoList" + loginName + time;
        String result = HttpRequest.post(queryPowerInfoListUrl)
                .form("LoginName",loginName)
                .form("Password",encode(text,loginKey))
                .form("times",time)
                .execute().body();
        LOGGER.info("杭州西子电表获取设备列表接口请求接口返回数据:{}",result);
        if(StrUtil.isNotBlank(result)){
            JSONObject resultJson = JSONObject.parseObject(result);
            String code = resultJson.getString("code");
            if("1".equals(code)){
                JSONArray list = resultJson.getJSONArray("list");
                if(!list.isEmpty()){
                    //查询数据库是否存在
                    String apiNo = pullThirdDeviceRequestModel.getTbAccountDo().getApiNo();
                    List<TbDeviceDo> existDevices = deviceDataAccess.getDeviceListByOneApiNo(apiNo);
                    List<String> existDevicesUuid = existDevices.stream().map(TbDeviceDo::getDeviceThirdNo).collect(Collectors.toList());
                    //进行过滤操作，只处理未保存部分数据，其他数据从刷新接口就行刷新
                    JSONArray finalDatas = list;
                    list = new JSONArray(IntStream.range(0, list.size()).filter(i -> !existDevicesUuid.contains(finalDatas.getJSONObject(i).getString("uuid"))).mapToObj(list::getJSONObject).collect(Collectors.toList()));
                    //处理数据并插入,由于该厂商只存在电表数据，所以只插入电表
                    for (int i = 0; i < list.size(); i++) {
                        JSONObject deviceInfo = list.getJSONObject(i);
                        String powerNum = deviceInfo.getString("powernum");
                        String powerName = deviceInfo.getString("powername");
                        searchDetail(loginName, powerNum, loginKey, powerName, tbDeviceDos);
                    }
                }
            }else{
                LOGGER.info("杭州西子电表获取设备列表接口请求接口返回错误code:{},url:{},LoginName:{}",code,queryPowerInfoListUrl,loginName);
            }
        }
        return tbDeviceDos;
    }

    /**
     * 查询详情数据
     * @param loginName
     * @param powerNum
     * @param loginKey
     * @param powerName
     * @param tbDeviceDos
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     */
    private void searchDetail(String loginName, String powerNum, String loginKey, String powerName, List<TbDeviceDo> tbDeviceDos) throws NoSuchAlgorithmException, InvalidKeyException {
        long time;
        String text;
        String code;
        //重新查询数据，返回电表其他数据
        time = System.currentTimeMillis()/1000;
        String RoomID = "";
        text = loginName + "QueryPowerInfo" + loginName+RoomID + powerNum + time;
        String queryPowerInfoResult = HttpRequest.post(QueryPowerInfoUrl)
                .form("LoginName", loginName)
                .form("Password", encode(text, loginKey))
                .form("RoomID", RoomID)
                .form("PowerNum", powerNum)
                .form("times", time)
                .execute().body();
        if(StrUtil.isNotBlank(queryPowerInfoResult)){
            JSONObject queryPowerInfoResultJson = JSONObject.parseObject(queryPowerInfoResult);
            code = queryPowerInfoResultJson.getString("code");
            if("1".equals(code)){
                JSONArray list1 = queryPowerInfoResultJson.getJSONArray("list");
                if(!list1.isEmpty()){
                    JSONObject jsonObject = list1.getJSONObject(0);
                    if (Objects.nonNull(jsonObject)) {
                        TbDeviceDo tbDeviceDo = new TbDeviceDo();
                        Integer isOnline = Optional.ofNullable(jsonObject.getInteger("IsOnline")).orElse(0);
                        Integer state = Optional.ofNullable(jsonObject.getInteger("State")).orElse(0);
                        Double degreeNum = Optional.ofNullable(jsonObject.getDouble("DegreeNum")).orElse(0.0);
                        //默认杭州西子全部是电表
                        tbDeviceDo.setDeviceThirdNo(powerNum);
                        tbDeviceDo.setDeviceName(powerName);
                        tbDeviceDo.setDeviceModel("DDSY86");
                        tbDeviceDo.setReportTime(LocalDateTime.now());
                        tbDeviceDo.setOnlineStatus(isOnline == 1 ? 1 : 0);
                        tbDeviceDo.setPowerStatus(state == 11 ? 1 : 0);
                        tbDeviceDo.setCurrentReading(degreeNum);
                        tbDeviceDo.setDeviceType(DeviceTypeEnum.AMMETER.getCode());
                        tbDeviceDos.add(tbDeviceDo);
                    }
                }
            }
        }
    }

    /**
     * 刷新电表
     * @param tbDeviceDo
     * @param operateThirdDeviceRequestModel
     * @return
     * @throws Exception
     */
    @Override
    public AmmeterInfoResModel refreshAmmeterInfo(TbDeviceDo tbDeviceDo, OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        String[] accessToken = operateThirdDeviceRequestModel.getAccessToken().split("\\|");
        String loginName = "";
        String loginKey = "";
        if(accessToken.length==2){
            loginName=accessToken[0];
            loginKey=accessToken[1];
        }
        AmmeterInfoResModel ammeterInfoResModel = new AmmeterInfoResModel();
        String deviceThirdNo = tbDeviceDo.getDeviceThirdNo();
        long time = System.currentTimeMillis() / 1000;
        String RoomID = "";
        String text = loginName + "QueryPowerInfo" + loginName+RoomID + deviceThirdNo + time;
        //查询电表的详情数据
        String result = HttpRequest.post(QueryPowerInfoUrl)
                .form("LoginName", loginName)
                .form("Password", encode(text,loginKey))
                .form("RoomID", RoomID)
                .form("PowerNum", deviceThirdNo)
                .form("times", time)
                .execute().body();
        if(StrUtil.isNotBlank(result)){
            JSONObject queryPowerInfoResultJson = JSONObject.parseObject(result);
            if (Objects.nonNull(queryPowerInfoResultJson)) {
                String code = queryPowerInfoResultJson.getString("code");
                if("1".equals(code)){
                    JSONArray lists = queryPowerInfoResultJson.getJSONArray("list");
                    if(!lists.isEmpty()){
                        JSONObject data = lists.getJSONObject(0);
                        if (Objects.nonNull(data)) {
                            Integer isOnline = Optional.ofNullable(data.getInteger("IsOnline")).orElse(0);
                            Integer state = Optional.ofNullable(data.getInteger("State")).orElse(0);
                            Double degreeNum = Optional.ofNullable(data.getDouble("DegreeNum")).orElse(0.0);
                            String date = Optional.ofNullable(data.getString("ReadDate")).orElse(DateUtil.formatDate(new Date()));
                            ammeterInfoResModel.setReportTime(new Date(date));
                            ammeterInfoResModel.setCurrentReading(degreeNum);
                            ammeterInfoResModel.setOnlineStatus(isOnline == 1 ? 1 : 0);
                            ammeterInfoResModel.setPowerStatus(state == 11 ? 1 : 0);
                        }
                    }
                }
            }
        }
        return ammeterInfoResModel;
    }

    /**
     * 电表合闸
     * @param operateThirdDeviceRequestModel
     * @return
     * @throws Exception
     */
    @Override
    public OperateThirdDeviceResponseModel switchAmmeterOn(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        String[] accessToken = operateThirdDeviceRequestModel.getAccessToken().split("\\|");
        String loginName = "";
        String loginKey = "";
        if(accessToken.length==2){
            loginName=accessToken[0];
            loginKey=accessToken[1];
        }
        OperateThirdDeviceResponseModel operateThirdDeviceResponseModel = new OperateThirdDeviceResponseModel();
        String PowerNum = operateThirdDeviceRequestModel.getDeviceThirdNo();
        String IsOn = "1";
        long time = System.currentTimeMillis()/1000;
        String text = loginName+"ChangePowerState"+loginName+PowerNum+IsOn+ time;
        String result = HttpRequest.post(changePowerStateUrl)
                .form("LoginName", loginName)
                .form("Password", encode(text,loginKey))
                .form("PowerNum",PowerNum )
                .form("IsOn", IsOn)
                .form("times", time)
                .execute().body();
        if(StrUtil.isNotBlank(result)){
            JSONObject resultJson = JSONObject.parseObject(result);
            String code = resultJson.getString("code");
            if("1".equals(code)){
                operateThirdDeviceResponseModel.setOperateResult(Boolean.TRUE);
            }else{
                operateThirdDeviceResponseModel.setOperateResult(Boolean.FALSE);
                operateThirdDeviceResponseModel.setOperateMessage(resultJson.getString("msg"));
            }
        }
        return operateThirdDeviceResponseModel;
    }

    /**
     * 电表关闸
     * @param operateThirdDeviceRequestModel
     * @return
     * @throws Exception
     */
    @Override
    public OperateThirdDeviceResponseModel switchAmmeterOff(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        String[] accessToken = operateThirdDeviceRequestModel.getAccessToken().split("\\|");
        String loginName = "";
        String loginKey = "";
        if(accessToken.length==2){
            loginName=accessToken[0];
            loginKey=accessToken[1];
        }
        OperateThirdDeviceResponseModel operateThirdDeviceResponseModel = new OperateThirdDeviceResponseModel();
        String PowerNum = operateThirdDeviceRequestModel.getDeviceThirdNo();
        String IsOn = "0";
        long time = System.currentTimeMillis()/1000;
        String text = loginName+"ChangePowerState"+loginName+PowerNum+IsOn+ time;
        String result = HttpRequest.post(changePowerStateUrl).form("LoginName", loginName)
                .form("Password", encode(text,loginKey))
                .form("PowerNum",PowerNum )
                .form("IsOn", IsOn)
                .form("times", time)
                .execute().body();
        if(StrUtil.isNotBlank(result)){
            JSONObject resultJson = JSONObject.parseObject(result);
            String code = resultJson.getString("code");
            if("1".equals(code)){
                operateThirdDeviceResponseModel.setOperateResult(Boolean.TRUE);
            }else{
                operateThirdDeviceResponseModel.setOperateResult(Boolean.FALSE);
                operateThirdDeviceResponseModel.setOperateMessage(resultJson.getString("msg"));
            }
        }
        return operateThirdDeviceResponseModel;
    }


    /**
     * 加密
     * @param text
     * @param secret
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     */
    public String encode(String text,String secret) throws NoSuchAlgorithmException, InvalidKeyException {
        Mac sha256_HMAC = Mac.getInstance("HmacSHA1");
        SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA1");
        sha256_HMAC.init(secret_key);
        return java.util.Base64.getEncoder().encodeToString(sha256_HMAC.doFinal(text.getBytes(StandardCharsets.UTF_8)));
    }
}
